﻿/** \file
* \$Rev: 106 $
* 
* \$Date: 2011-04-12 22:55:10 +0000 (Tue, 12 Apr 2011) $
*
* \$URL: http://benfwaves.googlecode.com/svn/branches/fftw/FFTW/PInvoke.cs $
*/

using System;
using System.Runtime.InteropServices;

namespace FFTW
{
	/// <summary>
	/// An object representing choices for a certain FFTW p/invoke function
	/// for every floating-point flavour of the FFTW library (currently float
	/// or double).
	/// </summary>
	/// <typeparam name="DelType">The p/invoke delegate type.</typeparam>
	public class DelChoices<DelType>
	{
		/// <summary>
		/// The delegate in the float library.
		/// </summary>
		readonly DelType delFloat;
		/// <summary>
		/// The delegate in the double library.
		/// </summary>
		readonly DelType delDouble;

		/// <summary>
		/// Construct a delegate choice object.
		/// </summary>
		/// <param name="delFloat">The delegate in the float library.</param>
		/// <param name="delDouble">The delegate in the double library.</param>
		public DelChoices(DelType delFloat,
			DelType delDouble)
		{
			this.delFloat = delFloat;
			this.delDouble = delDouble;
		}

		/// <summary>
		/// Get the right delegate according to whether the float or double
		/// library is being used.
		/// </summary>
		/// <typeparam name="ElementType">Float or double.</typeparam>
		/// <returns>A p/invoke delegate.</returns>
		public DelType GetDel<ElementType>()
			where ElementType : struct
		{
			if (typeof(ElementType) == typeof(float))
				return delFloat;
			else if (typeof(ElementType) == typeof(double))
				return delDouble;
			else throw new ArgumentException();
		}
	}

	/// <summary>
	/// All p/invoke functions for the FFTW library.
	/// </summary>
	static class PInvoke
	{
		/// <summary>The name of the float dll.</summary>
		const string dllNameFloat = "libfftw3f-3.dll";
		/// <summary>The name of the double dll.</summary>
		const string dllNameDouble = "libfftw3-3.dll";

		/// <summary>Allocate aligned memory.</summary>
		/// <param name="nbytes">The number of bytes to allocate.</param>
		/// <returns>An unmanaged, aligned memory buffer.</returns>
		public delegate IntPtr del_malloc(int nbytes);
		/// See <see cref="del_malloc"/>
		public static readonly DelChoices<del_malloc> malloc =
			new DelChoices<del_malloc>(fftwf_malloc, fftw_malloc);
		/// See <see cref="del_malloc"/>
		[DllImport(dllNameFloat, CallingConvention = CallingConvention.Cdecl)]
		static extern IntPtr fftwf_malloc(int nbytes);
		/// See <see cref="del_malloc"/>
		[DllImport(dllNameDouble, CallingConvention = CallingConvention.Cdecl)]
		static extern IntPtr fftw_malloc(int nbytes);

		/// <summary>Deallocate aligned memory.</summary>
		/// <param name="handle">
		/// A handle to a buffer that must have been allocated with fftw_malloc.
		/// </param>
		public delegate void del_free(IntPtr handle);
		/// See <see cref="del_free"/>
		public static readonly DelChoices<del_free> free =
			new DelChoices<del_free>(fftwf_free, fftw_free);
		/// See <see cref="del_free"/>
		[DllImport(dllNameFloat, CallingConvention = CallingConvention.Cdecl)]
		static extern void fftwf_free(IntPtr handle);
		/// See <see cref="del_free"/>
		[DllImport(dllNameDouble, CallingConvention = CallingConvention.Cdecl)]
		static extern void fftw_free(IntPtr handle);

		/// <summary>Cleanup all FFTW resources.</summary>
		public delegate void del_cleanup();
		/// See <see cref="del_cleanup"/>
		public static readonly DelChoices<del_cleanup> cleanup =
			new DelChoices<del_cleanup>(fftwf_cleanup, fftw_cleanup);
		/// See <see cref="del_cleanup"/>
		[DllImport(dllNameFloat, CallingConvention = CallingConvention.Cdecl)]
		static extern void fftwf_cleanup();
		/// See <see cref="del_cleanup"/>
		[DllImport(dllNameDouble, CallingConvention = CallingConvention.Cdecl)]
		static extern void fftw_cleanup();

		/// <summary>Execute a given plan.</summary>
		/// <param name="handle">A handle to the plan to execute.</param>
		public delegate void del_execute(IntPtr handle);
		/// See <see cref="del_execute"/>
		public static readonly DelChoices<del_execute> execute =
			new DelChoices<del_execute>(fftwf_execute, fftw_execute);
		/// See <see cref="del_execute"/>
		[DllImport(dllNameFloat, CallingConvention = CallingConvention.Cdecl)]
		static extern void fftwf_execute(IntPtr handle);
		/// See <see cref="del_execute"/>
		[DllImport(dllNameDouble, CallingConvention = CallingConvention.Cdecl)]
		static extern void fftw_execute(IntPtr handle);

		/// <summary>Destroy a given plan.</summary>
		/// <param name="handle">A handle to the plan to destroy.</param>
		public delegate void del_destroy_plan(IntPtr handle);
		/// See <see cref="del_destroy_plan"/>
		public static readonly DelChoices<del_destroy_plan> destroy_plan =
			new DelChoices<del_destroy_plan>(fftwf_destroy_plan, fftw_destroy_plan);
		/// See <see cref="del_destroy_plan"/>
		[DllImport(dllNameFloat, CallingConvention = CallingConvention.Cdecl)]
		static extern void fftwf_destroy_plan(IntPtr handle);
		/// See <see cref="del_destroy_plan"/>
		[DllImport(dllNameDouble, CallingConvention = CallingConvention.Cdecl)]
		static extern void fftw_destroy_plan(IntPtr handle);

		/// <summary>
		/// Create a plan for a one-dimensional complex-to-complex plan.
		/// </summary>
		/// <param name="n">The number of logical array elements.</param>
		/// <param name="in">The input array.</param>
		/// <param name="out">The output array.</param>
		/// <param name="direction">The direction of the transform.</param>
		/// <param name="flags">The plan creation flags.</param>
		/// <returns>A handle to the plan.</returns>
		public delegate IntPtr del_plan_dft_1d(int n, IntPtr @in, IntPtr @out,
			Direction direction, PlanFlags flags);
		/// See <see cref="del_plan_dft_1d"/>
		public static readonly DelChoices<del_plan_dft_1d> plan_dft_1d =
			new DelChoices<del_plan_dft_1d>(fftwf_plan_dft_1d, fftw_plan_dft_1d);
		/// See <see cref="del_plan_dft_1d"/>
		[DllImport(dllNameFloat, CallingConvention = CallingConvention.Cdecl)]
		static extern IntPtr fftwf_plan_dft_1d(
			int n, IntPtr @in, IntPtr @out, Direction direction, PlanFlags flags);
		/// See <see cref="del_plan_dft_1d"/>
		[DllImport(dllNameDouble, CallingConvention = CallingConvention.Cdecl)]
		static extern IntPtr fftw_plan_dft_1d(
			int n, IntPtr @in, IntPtr @out, Direction direction, PlanFlags flags);

		/// <summary>
		/// Plan a one-dimensional complex-to-real transform.
		/// </summary>
		/// <param name="n">The number of logical array elements.</param>
		/// <param name="in">The input array.</param>
		/// <param name="out">The output array.</param>
		/// <param name="flags">The plan creation flags.</param>
		/// <returns>A handle to the plan.</returns>
		public delegate IntPtr del_plan_dft_c2r_1d(
			int n, IntPtr @in, IntPtr @out, PlanFlags flags);
		/// See <see cref="del_plan_dft_c2r_1d"/>
		public static readonly DelChoices<del_plan_dft_c2r_1d>
			plan_dft_c2r_1d = new DelChoices<del_plan_dft_c2r_1d>
				(fftwf_plan_dft_c2r_1d, fftw_plan_dft_c2r_1d);
		/// See <see cref="del_plan_dft_c2r_1d"/>
		[DllImport(dllNameFloat, CallingConvention = CallingConvention.Cdecl)]
		static extern IntPtr fftwf_plan_dft_c2r_1d(
			int n, IntPtr @in, IntPtr @out, PlanFlags flags);
		/// See <see cref="del_plan_dft_c2r_1d"/>
		[DllImport(dllNameDouble, CallingConvention = CallingConvention.Cdecl)]
		static extern IntPtr fftw_plan_dft_c2r_1d(
			int n, IntPtr @in, IntPtr @out, PlanFlags flags);

		/// <summary>
		/// Plan a one-dimensional real-to-complex transform.
		/// </summary>
		/// <param name="n">The number of logical array elements.</param>
		/// <param name="in">The input array.</param>
		/// <param name="out">The output array.</param>
		/// <param name="flags">The plan creation flags.</param>
		/// <returns>A handle to the plan.</returns>
		public delegate IntPtr del_plan_dft_r2c_1d(
			int n, IntPtr @in, IntPtr @out, PlanFlags flags);
		/// See <see cref="del_plan_dft_r2c_1d"/>
		public static readonly DelChoices<del_plan_dft_r2c_1d>
			plan_dft_r2c_1d = new DelChoices<del_plan_dft_r2c_1d>
				(fftwf_plan_dft_r2c_1d, fftw_plan_dft_r2c_1d);
		/// See <see cref="del_plan_dft_r2c_1d"/>
		[DllImport(dllNameFloat, CallingConvention = CallingConvention.Cdecl)]
		static extern IntPtr fftwf_plan_dft_r2c_1d(
			int n, IntPtr @in, IntPtr @out, PlanFlags flags);
		/// See <see cref="del_plan_dft_r2c_1d"/>
		[DllImport(dllNameDouble, CallingConvention = CallingConvention.Cdecl)]
		static extern IntPtr fftw_plan_dft_r2c_1d(
			int n, IntPtr @in, IntPtr @out, PlanFlags flags);

		/// <summary>
		/// Plan a one-dimensional real-to-real transform.
		/// </summary>
		/// <param name="n">The number of logical array elements.</param>
		/// <param name="in">The input array.</param>
		/// <param name="out">The output array.</param>
		/// <param name="kind">The real-to-real transform kind.</param>
		/// <param name="flags">The plan creation flags.</param>
		/// <returns>A handle to the plan.</returns>
		public delegate IntPtr del_plan_r2r_1d(
			int n, IntPtr @in, IntPtr @out, R2RKind kind, PlanFlags flags);
		/// See <see cref="del_plan_r2r_1d"/>
		public static readonly DelChoices<del_plan_r2r_1d> plan_r2r_1d =
			new DelChoices<del_plan_r2r_1d>(fftwf_plan_r2r_1d, fftw_plan_r2r_1d);
		/// See <see cref="del_plan_r2r_1d"/>
		[DllImport(dllNameFloat, CallingConvention = CallingConvention.Cdecl)]
		static extern IntPtr fftwf_plan_r2r_1d(
			int n, IntPtr @in, IntPtr @out, R2RKind kind, PlanFlags flags);
		/// See <see cref="del_plan_r2r_1d"/>
		[DllImport(dllNameDouble, CallingConvention = CallingConvention.Cdecl)]
		static extern IntPtr fftw_plan_r2r_1d(
			int n, IntPtr @in, IntPtr @out, R2RKind kind, PlanFlags flags);
	}
}
